import os
import json
from logging_config import setup_logging
from config_loader import load_frame_config
from protocol.frames.registry import get_frame_builder, get_frame_parser
from protocol.header import build_header, parse_header, build_common_config
from protocol.codec import xor_checksum, escape_bytes, unescape_bytes, to_hex, from_hex
from state_io import load_state, save_state
from version_manager import list_versions, validate_and_get_active_profile, get_frame_cfg_path_for_cmd, get_header_version


def encode_message(frame_id_str: str, profile: str = None, frame_config: dict = None, terminal_phone: str = None, **params) -> bytes:
    """编码消息为字节数据"""
    config_dir = './config'
    state = load_state()

    # 构建common配置，将SIM卡号处理逻辑封装在头部处理模块中
    common = build_common_config(terminal_phone)

    # 如果提供了自定义配置，使用它；否则从文件加载
    if frame_config:
        frame_cfg = frame_config
    else:
        # 通过版本管理模块定位配置文件
        frame_cfg_path, _ = get_frame_cfg_path_for_cmd(frame_id_str, profile)
        frame_cfg = load_frame_config(frame_cfg_path)

    # 处理顶层 simulators（从独立存储读取）
    simulator_values = _build_simulator_values(frame_id_str, profile or '')

    # 获取header版本（根据profile从metadata.json中获取）
    header_version = get_header_version(profile or '')

    frame_id = int(frame_id_str, 16)
    builder = get_frame_builder(frame_id)
    # 将 simulator_values 通过 params 传递
    body = builder(common=common, frame_cfg=frame_cfg, state=state, simulator_values=simulator_values, **params)

    # 构建header时传入版本信息
    header = build_header(
        frame_id=frame_id,
        body_length=len(body),
        common=common,
        state=state,
        header_version=header_version
    )

    content = header + body
    check = xor_checksum(content)
    framed = content + bytes([check])
    final_bytes = bytes([0x7e]) + escape_bytes(framed) + bytes([0x7e])
    save_state(state)
    return final_bytes


def _build_simulator_values(cmd_id: str, profile: str) -> dict:
    """
    从独立存储中读取模拟器配置并生成字段路径到值的映射表

    Args:
        cmd_id: 指令ID，如 "0x0200"
        profile: 版本标识，如 "sichuan/2025"

    Returns:
        字典，键为字段路径（如 "body.time"），值为模拟器生成的值
    """
    from protocol.simulators import create_simulator
    from gui.simulator_storage import load_simulators

    simulator_values = {}
    # 从独立存储加载模拟器配置
    simulators = load_simulators(profile, cmd_id)

    for sim in simulators:
        # 只处理启用的模拟器
        if not sim.get('enable', False):
            continue

        sim_type = sim.get('type')
        sim_config = sim.get('config', {})
        targets = sim.get('targets', [])

        try:
            # 创建模拟器实例
            simulator = create_simulator({'type': sim_type, **sim_config})

            # 生成值
            if sim_type == 'location':
                # 经纬度模拟器：targets 是字典 {"lat": "body.lat", "lng": "body.lng"}
                if isinstance(targets, dict):
                    location_data = simulator.generate()
                    for key, field_path in targets.items():
                        if key in location_data:
                            simulator_values[field_path] = location_data[key]
            else:
                # 时间/数值模拟器：targets 是数组 ["body.time", "body.xxx"]
                if isinstance(targets, list):
                    for field_path in targets:
                        value = simulator.generate(field_path)
                        simulator_values[field_path] = value
        except Exception as e:
            # 模拟器生成失败，跳过
            import logging
            sim_type = sim.get('type', 'unknown')
            logging.warning(f"{sim_type}模拟器生成失败: {e}")
            continue

    return simulator_values


def decode_message(frame_bytes: bytes, profile: str = None) -> dict:
    if len(frame_bytes) < 4 or frame_bytes[0] != 0x7e or frame_bytes[-1] != 0x7e:
        raise ValueError('帧边界无效')
    inner = frame_bytes[1:-1]
    raw = unescape_bytes(inner)
    config_dir = './config'
    
    # 解码时不需要SIM卡号，因为会从数据帧中解析出来
    # 使用默认配置进行解析
    common = build_common_config()
    
    # 解析header（自动识别版本）
    hdr, hdr_len = parse_header(raw, common)
    
    # 检测到的header版本
    detected_version = hdr.get('detectedHeaderVersion', '2019')
    
    # 如果提供了profile，验证版本一致性
    if profile:
        expected_version = get_header_version(profile)
        if detected_version != expected_version:
            raise ValueError(
                f'Header版本不匹配：数据帧检测到{detected_versi0on}版本，'
                f'但配置profile({profile})期望{expected_version}版本。'
                f'请检查数据帧格式或选择正确的协议版本。'
            )
    # 解析后的msgId与bodyAttr为十六进制字符串，内部计算需转换为整数
    _body_attr_val = hdr.get('bodyAttr')
    if isinstance(_body_attr_val, str) and _body_attr_val.startswith('0x'):
        body_attr_val = int(_body_attr_val, 16)
    else:
        body_attr_val = int(_body_attr_val)
    body_len = body_attr_val & 0x03FF
    start_body = hdr_len
    end_body = start_body + body_len
    if end_body + 1 > len(raw):
        raise ValueError('长度不匹配')
    body = raw[start_body:end_body]
    checksum = raw[end_body]
    if xor_checksum(raw[:end_body]) != checksum:
        raise ValueError('校验和不匹配')
    _msg_id_val = hdr.get('msgId')
    if isinstance(_msg_id_val, str) and _msg_id_val.startswith('0x'):
        frame_id = int(_msg_id_val, 16)
    else:
        frame_id = int(_msg_id_val)
    try:
        frame_cfg_path, _ = get_frame_cfg_path_for_cmd(f"0x{frame_id:04x}", profile)
        frame_cfg = load_frame_config(frame_cfg_path)
        state = load_state()
        parser = get_frame_parser(frame_id)
        decoded_body = parser(common=common, frame_cfg=frame_cfg, state=state, body_bytes=body)
        return { 'header': hdr, 'body': decoded_body }
    except FileNotFoundError as e:
        # 配置文件不存在，返回原始数据
        return { 
            'header': hdr, 
            'body': { 
                'error': f'未找到指令 0x{frame_id:04x} 的配置文件',
                'raw_data': body.hex(),
                'raw_length': len(body)
            }
        }
    except ValueError as e:
        if "不支持的帧ID" in str(e):
            # 不支持的指令ID
            return { 
                'header': hdr, 
                'body': { 
                    'error': f'不支持的指令ID: 0x{frame_id:04x}',
                    'raw_data': body.hex(),
                    'raw_length': len(body)
                }
            }
        else:
            raise


def get_active_profile():
    """获取活动版本配置"""
    versions = list_versions()
    env_profile = os.environ.get('JT_PROFILE') if 'JT_PROFILE' in os.environ else None
    return validate_and_get_active_profile(env_profile, versions, default_profile='sichuan/2025')


def get_versions():
    """获取所有可用版本"""
    return list_versions()






def run_test():
    """运行测试代码"""
    logger = setup_logging('INFO')
    active_profile = get_active_profile()
    
    # 编码示例
    frame = encode_message('0x0200', active_profile, None, '13800138000')
    hex_result = to_hex(frame)
    print(f"使用版本: {active_profile}")
    print(f"编码结果: {hex_result}")
    print(f"数据长度: {len(frame)} 字节")

    # 解码示例
    frame_2 = from_hex(hex_result)
    parsed = decode_message(frame_2, active_profile)
    # print(json.dumps(parsed, ensure_ascii=False, indent=2))


def run_gui():
    """启动GUI界面"""
    try:
        from gui.main_window import MainWindow
        print("正在启动GUI界面...")
        app = MainWindow()
        app.run()
    except Exception as e:
        print(f"启动GUI失败: {str(e)}")
        import traceback
        traceback.print_exc()
        input("按回车键退出...")


if __name__ == '__main__':
    # 启动GUI模式
    run_gui()

    # 命令行模式（测试代码）
    # run_test()


